package cn.zebra.dev.product.module.sku.service.impl;

import cn.zebra.dev.common.utils.DateUtils;
import cn.zebra.dev.common.utils.StrUtils;
import cn.zebra.dev.ibatis.plus.service.impl.ServiceImpl;
import cn.zebra.dev.product.module.sku.dao.ProductSkuDao;
import cn.zebra.dev.product.module.sku.entity.ProductSkuAttributeEntity;
import cn.zebra.dev.product.module.sku.entity.ProductSkuEntity;
import cn.zebra.dev.product.module.sku.service.ProductSkuAttributeService;
import cn.zebra.dev.product.module.sku.service.ProductSkuService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * @author runnable@sina.cn
 */
@Service
public class ProductSkuServiceImpl extends ServiceImpl<ProductSkuDao, ProductSkuEntity> implements ProductSkuService {

    @Autowired
    private ProductSkuAttributeService attributeService;

    /**
     * 根据商品sku表主键id查找商品sku对象
     *
     * @param productSkuId 商品sku表Id
     * @return 商品sku对象
     */
    @Override
    public ProductSkuEntity findById(Long productSkuId) {
        QueryWrapper<ProductSkuEntity> wrapper = new QueryWrapper<>();
        wrapper.apply("id = {0}", productSkuId);
        wrapper.apply("delete_flag = FALSE");
        return this.getOne(wrapper);
    }

    @Override
    public BigDecimal findUnitPriceByProductSkuId(Long productSkuId) {
        QueryWrapper<ProductSkuEntity> wrapper = new QueryWrapper<>();
        wrapper.select("unit_price");
        wrapper.apply("id = {0}", productSkuId);
        return getOne(wrapper).getUnitPrice();
    }

    @SneakyThrows
    @Override
    public Boolean save(Long productId, List<ProductSkuEntity> list, Long createId) {
        if (!CollectionUtils.isEmpty(list)) {
            LocalDateTime now = LocalDateTime.now();
            list.forEach(sku -> {
                setSku(sku);
                sku.setId(null);
                sku.setProductId(productId);
                sku.setProductSkuSn(System.currentTimeMillis());
                sku.setCreateId(createId);
                sku.setCreateTime(now);
                sku.setUpdateId(0L);
                sku.setUpdateTime(DateUtils.defaultTime());
                sku.setDeleteFlag(false);
            });
        }
        if (this.saveBatch(list)) {
            List<Future<Boolean>> futures = new ArrayList<>(list.size());
            list.forEach(productSkuEntity -> futures.add(asyncSaveSkuAttr(productId, productSkuEntity)));
            for (int i = futures.size() - 1; i >= 0; i--) {
                if (!futures.get(i).get()) {
                    return false;
                }
            }
        } else {
            return false;
        }
        return true;
    }

    @Override
    @Async
    public Future<Boolean> asyncSave(ProductSkuEntity entity) {
        return AsyncResult.forValue(this.save(entity));
    }

    /**
     * 批量线程保存
     *
     * @param entityList 商品分类集合
     * @return 成功返回true 空集合返回false 保存失败抛出异常
     */
    @SneakyThrows
    @Override
    public boolean saveBatch(Collection<ProductSkuEntity> entityList) {
        if (entityList != null && entityList.size() > 0) {
            List<Future<Boolean>> list = new ArrayList<>(entityList.size());
            entityList.forEach(entity -> list.add(this.asyncSave(entity)));
            for (int i = list.size() - 1; i >= 0; i--) {
                if (!list.get(i).get()) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    @SneakyThrows
    private boolean updateBatch(Collection<ProductSkuEntity> entityList) {
        if (entityList != null && entityList.size() > 0) {
            List<Future<Boolean>> list = new ArrayList<>(entityList.size());
            entityList.forEach(entity -> list.add(this.asyncUpdate(entity)));
            for (int i = list.size() - 1; i >= 0; i--) {
                if (!list.get(i).get()) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    @Async
    public Future<Boolean> asyncUpdate(ProductSkuEntity entity) {
        return AsyncResult.forValue(this.update(entity, "id = {0}", entity.getId()));
    }

    @SneakyThrows
    @Override
    public Boolean update(Long productId, List<ProductSkuEntity> list, Long updateId) {
        List<ProductSkuEntity> sourceSkuList = this.findListByProductId(productId);
        if (!CollectionUtils.isEmpty(list)) {
            LocalDateTime now = LocalDateTime.now();
            List<ProductSkuEntity> saveList = new ArrayList<>();
            List<ProductSkuEntity> updateList = new ArrayList<>();
            for (int i = list.size() - 1; i >= 0; i--) {
                ProductSkuEntity sku = list.get(i);
                setSku(sku);
                sku.setDeleteFlag(false);
                Long skuId = sku.getId();
                //如果存在id则修改
                if (skuId != null) {
                    //如果删除失败说明伪造id传递
                    if (!sourceSkuList.removeIf(sourceSku -> sourceSku.getId().equals(skuId))) {
                        return false;
                    }
                    sku.setCreateId(null);
                    sku.setCreateTime(null);
                    sku.setUpdateId(updateId);
                    sku.setUpdateTime(now);
                    updateList.add(sku);
                } else {
                    sku.setProductSkuSn(System.currentTimeMillis());
                    sku.setCreateId(updateId);
                    sku.setCreateTime(now);
                    sku.setUpdateId(0L);
                    sku.setUpdateTime(DateUtils.defaultTime());
                    saveList.add(sku);
                    list.remove(i);
                }
            }
            if (updateList.size() > 0 && !this.updateBatch(updateList)) {
                return false;
            }
            if (saveList.size() > 0 && !this.saveBatch(saveList)) {
                return false;
            }
            List<Future<Boolean>> futures = new ArrayList<>(saveList.size());
            //批量保存SKU规格属性
            saveList.forEach(productSkuEntity -> futures.add(asyncSaveSkuAttr(productId, productSkuEntity)));
            for (int i = futures.size() - 1; i >= 0; i--) {
                if (!futures.get(i).get()) {
                    return false;
                }
            }
        } else {
            return false;
        }
        //删除旧商品规格
        if (!CollectionUtils.isEmpty(sourceSkuList)) {
            ProductSkuEntity entity = new ProductSkuEntity();
            entity.setDeleteFlag(true);
            UpdateWrapper<ProductSkuEntity> wrapper = new UpdateWrapper<>();
            List<Long> skuIds = sourceSkuList.stream().map(ProductSkuEntity::getId).collect(Collectors.toList());
            wrapper.in("id", skuIds);
            if (!this.update(entity, wrapper)) {
                return false;
            }
            //删除旧商品SKU规格属性
            return attributeService.deleteByProductSkuIds(skuIds);
        }

        return true;
    }

    /**
     * 保存商品规格属性信息
     *
     * @param productId        商品id
     * @param productSkuEntity SKU对象
     * @return 保存成功返回True 保存失败返回False
     */
    private boolean saveSkuAttr(Long productId, ProductSkuEntity productSkuEntity) {
        Long productSkuId = productSkuEntity.getId();
        if (productSkuId == null) {
            return false;
        }
        List<ProductSkuAttributeEntity> attrEntities = productSkuEntity.getAttrEntities();
        if (attrEntities == null) {
            return false;
        }
        List<ProductSkuAttributeEntity> list = new ArrayList<>(attrEntities.size());
        attrEntities.forEach(attr -> {
            ProductSkuAttributeEntity entity = new ProductSkuAttributeEntity();
            entity.setProductId(productId);
            entity.setProductSkuId(productSkuId);
            entity.setAttributeId(attr.getId());
            entity.setAttributeKey(attr.getAttributeKey());
            entity.setAttributeValue(attr.getAttributeValue());
            list.add(entity);
        });
        return attributeService.saveBatch(list);
    }

    @Async
    public Future<Boolean> asyncSaveSkuAttr(Long productId, ProductSkuEntity productSkuEntity) {
        return AsyncResult.forValue(this.saveSkuAttr(productId, productSkuEntity));
    }

    /**
     * 设置SKU对象(主要防止数据库不存在默认值)
     *
     * @param sku SKU对象
     */
    private void setSku(ProductSkuEntity sku) {
        if (StrUtils.isBlank(sku.getProductSkuSn())) {
            sku.setProductSkuSn("");
        }
        if (sku.getCostPrice() == null) {
            sku.setCostPrice(BigDecimal.ZERO);
        }
        if (sku.getMarketPrice() == null) {
            sku.setMarketPrice(BigDecimal.ZERO);
        }
        if (sku.getWeight() == null) {
            sku.setWeight(BigDecimal.ZERO);
        }
        if (sku.getVolume() == null) {
            sku.setVolume(BigDecimal.ZERO);
        }
    }

    @Override
    public List<ProductSkuEntity> findListByProductId(Long productId) {
        QueryWrapper<ProductSkuEntity> wrapper = new QueryWrapper<>();
        wrapper.apply("product_id = {0}", productId);
        wrapper.apply("delete_flag = FALSE");
        return list(wrapper);
    }

    @Override
    public List<ProductSkuEntity> findByIds(Collection<Long> skuIds) {
        if (skuIds == null || skuIds.size() == 0) {
            return new ArrayList<>();
        }
        QueryWrapper<ProductSkuEntity> wrapper = new QueryWrapper<>();
        wrapper.in("id", skuIds);
        return this.list(wrapper);
    }

    /**
     * 根据product_id集合查找多个sku对象集合
     *
     * @param productIds 商品id集合
     * @return sku对象集合
     */
    @Override
    public List<ProductSkuEntity> findListByProductIds(Collection<Long> productIds) {
        QueryWrapper<ProductSkuEntity> wrapper = new QueryWrapper<>();
        wrapper.in("product_id", productIds);
        return this.list(wrapper);
    }
}
